﻿using System.Drawing;
using System.Text.Json.Serialization.Metadata;
using DimensionsHelper.Common.Contracts.Excel;
using DimensionsHelper.Common.Excel;

namespace DimensionsHelper.ExcelAddIn.Core.Sql;

public class CodeMapBuilder : ExcelAddInBase<CodeMapSettings, CodeMapSettingsTransmission>
{

    private class WorkSheetCodeMap
    {
        public WorkSheetCodeMap(IExcelWorksheetOperator worksheet, CodeMap map)
        {
            Worksheet = worksheet;
            Map = map;
        }

        public IExcelWorksheetOperator Worksheet { get; }

        public CodeMap Map { get; }
    }


    private static readonly ExcelStyleColor WhiteColor = Color.White.ToExcelColor();


    private CodeMap _codeMap = new();
    private readonly List<WorkSheetCodeMap> _codeMaps = [];


    protected override LocalSettingService<CodeMapSettings> SettingService => new("CodeMapBuilder",
        JsonContext.Default.CodeMapSettings);

    protected override JsonTypeInfo<CodeMapSettingsTransmission> TransmissionJsonTypeInfo =>
        JsonContext.Default.CodeMapSettingsTransmission;


    public override void Run(IExcelWorkbookOperator workbook)
    {
        _codeMaps.Clear();

        if (Settings.CodeColumns.Length == 0 || Settings.LabelColumns.Length == 0)
        {
            return;
        }

        if (workbook.ContainsWorksheet(Properties.Resources.DefaultSettingSheetName))
        {
            ReadSettings(workbook.GetWorksheet(Properties.Resources.DefaultSettingSheetName));
        }

        foreach (IExcelWorksheetOperator worksheet in workbook.Worksheets)
        {
            // 跳过设置页
            if (worksheet.Name == Properties.Resources.DefaultSettingSheetName)
            {
                continue;
            }

            ReadSheet(worksheet);
        }
    }


    private int FindColorLevel(ExcelStyleColor color)
    {
        // 如果未指定背景颜色，所有颜色都视为第一级级别
        if (Settings.ColorLevels.Length == 0 || Settings.ColorLevels.All(e => e.Length == 0))
        {
            return 0;
        }

        int argb = color.ToArgb();

        for (int i = 0; i < Settings.ColorLevels.Length; i++)
        {
            if (Settings.ColorLevels[i].Contains(argb))
            {
                return i;
            }
        }

        return -1;
    }


    private void ReadRow(IExcelWorksheetOperator sheet, int row, out string code, out string label, out int level)
    {
        code = string.Empty;
        label = string.Empty;
        level = -1;

        int[][] columns = [Settings.CodeColumns, Settings.LabelColumns];

        for (int i = 0; i < columns.Length; i++)
        {
            foreach (var col in columns[i])
            {
                if (level > -1 && ((i == 0 && !string.IsNullOrEmpty(code)) || (i == 1 && !string.IsNullOrEmpty(label))))
                {
                    break;
                }

                var cell = sheet.GetRange(row, col);

                if (level == -1 && Settings.LevelMarkType == CodeLevelMarkType.InteriorColor)
                {
                    var color = cell.BackgroundColor;
                    if (color != ExcelStyleColor.Empty && color != WhiteColor)
                    {
                        level = FindColorLevel(color);
                    }
                }
                else if (level == -1 && Settings.LevelMarkType == CodeLevelMarkType.FontColor)
                {
                    level = FindColorLevel(cell.FontColor);
                }
                else if (level == -1 && (
                    (Settings.LevelMarkType == CodeLevelMarkType.FontBold && (cell.FontStyle & FontType.Bold) != 0) ||
                    (Settings.LevelMarkType == CodeLevelMarkType.FontItalic && (cell.FontStyle & FontType.Italic) != 0) ||
                    (Settings.LevelMarkType == CodeLevelMarkType.FontUnderline && (cell.FontStyle & FontType.Underline) != 0)
                ))
                {
                    level = 0;
                }

                if (cell == null || cell.Value?.ToString() is not { } text)
                {
                    continue;
                }

                if (i == 0 && !string.IsNullOrEmpty(code))
                {
                    code = text;
                }
                else if (!string.IsNullOrEmpty(label))
                {
                    label = text;
                }
            }
        }

        if (Settings.LevelMarkType == CodeLevelMarkType.WithoutCode && level == -1)
        {
            level = 0;
        }
    }


    private void ReadSheet(IExcelWorksheetOperator worksheet)
    {
        _codeMap = new CodeMap();
        _codeMaps.Add(new WorkSheetCodeMap(worksheet, _codeMap));

        CodeMapElementLevel? currentLevel = null;

        for (int i = Math.Max(1, Settings.StartRow); i <= worksheet.EndRow; i++)
        {
            ReadRow(worksheet, i, out string code, out string label, out int level);
            
            bool codeEmpty = string.IsNullOrWhiteSpace(code);
            bool labelEmpty = string.IsNullOrWhiteSpace(label);
            // Code 和 Label 不能同时是空
            if (codeEmpty && labelEmpty)
            {
                continue;
            }
            // Code 是空时，level需要大于-1
            if (codeEmpty && level == -1)
            {
                continue;
            }

            CodeMapElement element;
            // 如果 level > -1，创建码号级别
            if (level > -1)
            {
                element = new CodeMapElementLevel(currentLevel, code, label);
                
                // 如果当前级别大于查找到的级别，向上查找目标级别
                if (currentLevel != null && currentLevel.Level >= level)
                {
                    currentLevel = currentLevel.FindLevel(level);
                }

                // 如果当前没有级别，添加到表中
                if (currentLevel == null)
                {
                    _codeMap.AddElement(element);
                }
                
                currentLevel = (CodeMapElementLevel)element;
            }
            else
            {
                element = new CodeMapElement(currentLevel, code, label);
                _codeMap.AddElement(element);
            }
        }
    }


    private const string StartRowDescription = "起始行";
    private const string CodeColumnsDescription = "码号列";
    private const string LabelColumnsDescription = "描述列";
    private const string CodeLevelMarkTypeDescription = "码号级别标记类型";
    private const string CodeLevelOrderTypeDescription = "代码级别组织方式";
    private const string CodeLevelBehaviorDescription = "代码级别处理方式";
    private const string CodeLevelColorDescription = "代码级别颜色";


    private const string CodeLevelJoined = "追加到主列表中";
    private const string CodeLevelIndividual = "单独的列表";

    // Setting工作表格式
    // | StartRow |  CodeColumns |  LabelColumns  |   LevelMarkType  |  LevelBehavior  |   LevelColors  |
    // |  Number  |     Num1     |     Num1       |       Enum       |      |  YES/NO  |     BgColor1   |  BgColor2  | BgColor3 | ...
    //            |     Num2     |     Num2       |   LevelOrderType |      |  YES/NO  |        ...   
    //            |     ...      |     ...        |       Enum       |      |  YES/NO  |
    //            |     ...      |     ...        |                  |      |  YES/NO  |
    //            |     ...      |     ...        |                  |      |  YES/NO  |

    private void FormatSettingSheet(IExcelWorksheetOperator sheet)
    {
        // StartRow
        SetDescriptionCenter(sheet, 1, 1, StartRowDescription);
        SetIntegerValidation(sheet, 2, 1, 1).Value = 1;
        // CodeColumns
        SetDescriptionCenter(sheet, 1, 2, CodeColumnsDescription);
        SetIntegerValidation(sheet, 2, 2, 10, 2, 1);
        // 填充设置值
        var codeColumns = Settings.CodeColumns.Select(e => e > 0).ToArray();
        if (codeColumns.Length > 0)
        {
            sheet.GetRange(2, 2, 2 + codeColumns.Length, 2).Value = codeColumns.ToExcelColumn();
        }
        // LabelColumns
        SetDescriptionCenter(sheet, 1, 3, LabelColumnsDescription);
        SetIntegerValidation(sheet, 2, 3, 10, 3, 1);
        // 填充设置值
        var labelColumns = Settings.LabelColumns.Select(e => e > 0).ToArray();
        if (labelColumns.Length > 0)
        {
            sheet.GetRange(2, 3, 2 + labelColumns.Length, 3).Value = labelColumns.ToExcelColumn();
        }
        // LevelMarkType
        SetDescriptionCenter(sheet, 1, 4, CodeLevelMarkTypeDescription);
        SetListValidation(sheet, 2, 4, MakeEnumValidationList<CodeLevelMarkType>(), 
            Settings.LevelMarkType.ToString().ToUpper());
        // LevelOrderType
        SetDescriptionCenter(sheet, 3, 4, CodeLevelOrderTypeDescription);
        SetListValidation(sheet, 4, 4, MakeEnumValidationList<CodeLevelOrderType>(),
            Settings.OrderType.ToString().ToUpper());
        // LevelBehavior
        SetDescriptionCenter(sheet, 1, 5, CodeLevelBehaviorDescription);
        sheet.GetRange(1, 5, 1, 6).Merge();
        SetDescriptionCenter(sheet, 2, 5, CodeLevelJoined);
        SetBooleanValidation(sheet, 2, 6, (Settings.LevelBehavior & CodeLevelBehavior.Joined) != 0);
        SetDescriptionCenter(sheet, 3, 5, CodeLevelIndividual);
        SetBooleanValidation(sheet, 3, 6, (Settings.LevelBehavior & CodeLevelBehavior.Individual) != 0);
        // LevelColors
        SetDescriptionCenter(sheet, 1, 7, CodeLevelColorDescription);
        // 填充设置值
        for (int i = 0; i < Settings.ColorLevels.Length; i++)
        {
            int[] colors = Settings.ColorLevels[i];
            int col = 7;
            for (int j = 0; j < colors.Length; j++)
            {
                var color = colors[j];
                if (color == 0 || WhiteColor == color)
                {
                    continue;
                }
                sheet.GetRange(i + 2, col).BackgroundColor = ExcelStyleColor.FromArgb(color);
                col++;
            }
        }
        // 自动设置列宽
        sheet.AutoFitEntireColumns();
    }


    private static int[] ReadIntegerColumn(IExcelWorksheetOperator sheet, int startRow, int column)
    {
        int row = startRow;
        var values = new List<int>();
        while (true)
        {
            int val = ReadAsInteger(sheet, row, column);

            if (val == 0)
            {
                break;
            }

            values.Add(val);
            row++;
        }

        return values.ToArray();
    }


    private void ReadSettings(IExcelWorksheetOperator worksheet)
    {
        Settings.StartRow = ReadAsInteger(worksheet, 2, 1);
        // [2,2]向下查找
        Settings.CodeColumns = ReadIntegerColumn(worksheet, 2, 2);
        // [2,3]向下查找
        Settings.LabelColumns = ReadIntegerColumn(worksheet, 2, 3);
        // [2,4] - LevelMarkType
        Settings.LevelMarkType = ReadAsEnum<CodeLevelMarkType>(worksheet, 2, 4);
        // [4,4] - LevelOrderType
        Settings.OrderType = ReadAsEnum<CodeLevelOrderType>(worksheet, 4, 4);
        // LevelBehavior
        Settings.LevelBehavior = CodeLevelBehavior.None;
        if (ReadAsBoolean(worksheet, 2, 5))
        {
            Settings.LevelBehavior |= CodeLevelBehavior.Joined;
        }

        if (ReadAsBoolean(worksheet, 3, 5))
        {
            Settings.LevelBehavior |= CodeLevelBehavior.Individual;
        }
        
        // LevelColors
    }


    public override void BuildSettingSheet(IExcelWorkbookOperator workbook)
    {
        workbook.DeleteWorksheet(Properties.Resources.DefaultSettingSheetName);
        IExcelWorksheetOperator sheet = workbook.GetWorksheet(Properties.Resources.DefaultSettingSheetName);
        // 移动到最后
        sheet.MoveToEnd();
        // 添加格式
        FormatSettingSheet(sheet);
    }

}
